﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Text.RegularExpressions;
using YanZhiwei.DotNet2.Utilities.Base;

namespace YanZhiwei.DotNet2.Utilities.Common
{
    /// <summary>
    /// 双向绑定帮助类
    ///<para>参考:</para> 
    ///<para> http://blogs.msdn.com/b/winformsue/archive/2007/12/06/filtering-code.aspx </para>
    ///<para> http://blogs.msdn.com/b/winformsue/archive/2007/12/07/implementing-the-ibindinglistview-for-filtering.aspx </para>
    ///<para> http://www.codeproject.com/Articles/19867/How-To-Allow-To-Sort-By-Multiple-Columns-in-Custom </para>
    ///<para> http://msdn.microsoft.com/zh-cn/library/ms993236.aspx </para>
    ///<para> http://www.codeproject.com/Articles/37671/Databinding-BindingList-BindingSource-and-Busine </para>
    ///<para> http://www.dotblogs.com.tw/yc421206/archive/2013/09/03/116162.aspx </para>
    /// </summary>
    /// <typeparam name="T">泛型</typeparam>
    public class BindList<T> : BindingList<T>, IBindingListView
    {
        #region  构造函数以及私有，共有变量
        /// <summary>
        /// 构造函数
        /// </summary>
        public BindList()
            : base(new List<T>())
        {
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="List"></param>
        public BindList(IList<T> List)
            : base(List)
        {
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="Enumerable"></param>
        public BindList(IEnumerable<T> Enumerable)
            : base(new List<T>(Enumerable))
        {
        }
        private ListSortDescriptionCollection listSortDescription;
        private List<PropertyComparer<T>> propertyComparer;
        private readonly Dictionary<string, PropertyComparer<T>> comparerList = new Dictionary<string, PropertyComparer<T>>();
        private ListSortDirection sortDirection;
        private PropertyDescriptor propertyDesc;
        /// <summary>
        /// ListSortDescriptionCollection
        /// </summary>
        public ListSortDescriptionCollection SortDescriptions
        {
            get { return listSortDescription; }
        }
        /// <summary>
        /// SupportsAdvancedSorting
        /// </summary>
        public bool SupportsAdvancedSorting
        {
            get { return true; }
        }
        /// <summary>
        /// IsSortedCore
        /// </summary>
        protected override bool IsSortedCore
        {
            get
            {
                return true;
            }
        }
        private int CompareValuesByProperties(T x, T y)
        {
            if (x == null)
                return (y == null) ? 0 : -1;
            else
            {
                if (y == null)
                    return 1;
                else
                {
                    foreach (PropertyComparer<T> comparer in propertyComparer)
                    {
                        int retval = comparer.Compare(x, y);
                        if (retval != 0)
                            return retval;
                    }
                    return 0;
                }
            }

        }

        #endregion
        #region 重写ApplySortCore方法
        /// <summary>
        /// 重写ApplySortCore方法
        /// </summary>
        /// <param name="property">PropertyDescriptor</param>
        /// <param name="sortDirection">ListSortDirection</param>
        protected override void ApplySortCore(PropertyDescriptor property, ListSortDirection sortDirection)
        {
            List<T> _list = (List<T>)this.Items;
            string _name = property.Name;
            PropertyComparer<T> _comparer;

            if (!this.comparerList.TryGetValue(_name, out _comparer))
            {
                _comparer = new PropertyComparer<T>(property, sortDirection);
                this.comparerList.Add(_name, _comparer);
            }
            _comparer.SetDirection(sortDirection);
            _list.Sort(_comparer);
            this.propertyDesc = property;
            this.sortDirection = sortDirection;
            this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
        }
        #endregion
        #region 应用排序
        /// <summary>
        /// 应用排序
        /// </summary>
        /// <param name="sorts">ListSortDescriptionCollection</param>
        public void ApplySort(ListSortDescriptionCollection sorts)
        {
            //获取未排序集合
            List<T> _items = this.Items as List<T>;

            //若集合不等于NULL，则应用排序
            if (_items != null)
            {
                listSortDescription = sorts;
                propertyComparer = new List<PropertyComparer<T>>();
                foreach (ListSortDescription sort in sorts)
                    propertyComparer.Add(new PropertyComparer<T>(sort.PropertyDescriptor,
                        sort.SortDirection));
                _items.Sort(CompareValuesByProperties);
                //_isSorted = true;
            }
            else
            {
                //_isSorted = false;
            }
            this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
        }
        #endregion
        #region IBindingListView 成员
        #region 私有，共有变量
        List<T> unfilteredListValue = new List<T>();
        /// <summary>
        /// 未筛选集合
        /// </summary>
        public List<T> UnfilteredList
        {
            get { return unfilteredListValue; }
        }
        private string filterValue = null;
        /// <summary>
        /// 筛选表达式字符串
        /// </summary>
        public string Filter
        {
            get
            {
                return filterValue;
            }
            set
            {
                if (filterValue != value)
                {
                    RaiseListChangedEvents = false;
                    if (value == null)
                    {
                        this.ClearItems();
                        foreach (T t in unfilteredListValue)
                            this.Items.Add(t);
                        filterValue = value;
                    }
                    // If the value is empty string, do nothing.
                    // This behavior is compatible with DataGridView
                    // AutoFilter code.

                    else if (value == "") { }
                    // If the value is not null or string, than process
                    // normal.
                    else if (Regex.Matches(value, "[?[\\w ]+]? ?[=] ?'?[\\w|/: ]+'?", RegexOptions.Singleline).Count == 1)
                    {
                        // If the filter is not set.
                        unfilteredListValue.Clear();
                        unfilteredListValue.AddRange(this.Items);
                        filterValue = value;
                        GetFilterParts();
                        ApplyFilter();
                    }
                    else if (Regex.Matches(value, "[?[\\w ]+]? ?[=] ?'?[\\w|/: ]+'?", RegexOptions.Singleline).Count > 1)
                        throw new ArgumentException("Multi-column" + "filtering is not implemented.");
                    else
                        throw new ArgumentException("Filter is not" + "in the format: propName = 'value'.");
                    RaiseListChangedEvents = true;
                    OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));

                }
            }
        }
        private void GetFilterParts()
        {
            string[] _filterParts = Filter.Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries);
            filterPropertyNameValue = _filterParts[0].Replace("[", "").Replace("]", "").Trim();
            PropertyDescriptor propDesc = TypeDescriptor.GetProperties(typeof(T))[filterPropertyNameValue.ToString()];
            if (propDesc != null)
            {
                try
                {
                    TypeConverter converter = TypeDescriptor.GetConverter(propDesc.PropertyType);
                    filterCompareValue = converter.ConvertFromString(_filterParts[1].Replace("'", "").Trim());
                }
                catch (NotSupportedException)
                {
                    throw new ArgumentException("Specified filter value " + FilterCompare + " can not be converted from string." + "..Implement a type converter for " + propDesc.PropertyType.ToString());
                }
            }
            else
                throw new ArgumentException("Specified property '" + FilterPropertyName + "' is not found on type " + typeof(T).Name + ".");

        }
        private void ApplyFilter()
        {
            unfilteredListValue.Clear();
            unfilteredListValue.AddRange(this.Items);
            List<T> results = new List<T>();
            PropertyDescriptor propDesc = TypeDescriptor.GetProperties(typeof(T))[FilterPropertyName];
            if (propDesc != null)
            {
                int tempResults = -1;
                do
                {
                    tempResults = FindCore(tempResults + 1, propDesc, FilterCompare);
                    if (tempResults != -1)
                        results.Add(this[tempResults]);
                } while (tempResults != -1);
            }
            this.ClearItems();
            if (results != null && results.Count > 0)
            {
                foreach (T itemFound in results)
                    this.Add(itemFound);
            }
        }
        private string filterPropertyNameValue;
        private Object filterCompareValue;
        /// <summary>
        /// 属性筛选
        /// </summary>
        public string FilterPropertyName
        {
            get { return filterPropertyNameValue; }
        }
        /// <summary>
        /// FilterCompare
        /// </summary>
        public Object FilterCompare
        {
            get { return filterCompareValue; }
        }
        #endregion
        #region 移除筛选
        /// <summary>
        /// 移除筛选
        /// </summary>
        public void RemoveFilter()
        {
            if (Filter != null)
                Filter = null;
        }
        #endregion
        #region 是否支持筛选
        /// <summary>
        /// 是否支持筛选
        /// </summary>
        public bool SupportsFiltering
        {
            get { return true; }
        }
        #endregion
      
        #region 重写FindCore方法
        /// <summary>
        /// 重写FindCore方法
        /// </summary>
        /// <param name="prop">PropertyDescriptor</param>
        /// <param name="key">object</param>
        /// <returns>符合条数</returns>
        protected override int FindCore(PropertyDescriptor prop, object key)
        {
            // Get the property info for the specified property.
            PropertyInfo propInfo = typeof(T).GetProperty(prop.Name);
            T item;
            if (key != null)
            {
                // Loop through the items to see if the key
                // value matches the property value.
                for (int i = 0; i < Count; ++i)
                {
                    item = (T)Items[i];
                    if (propInfo.GetValue(item, null).Equals(key))
                        return i;

                }
            }
            return -1;
        }
        /// <summary>
        ///  重写FindCore方法
        /// </summary>
        /// <param name="startIndex">开始索引</param>
        /// <param name="prop">PropertyDescriptor</param>
        /// <param name="key">object</param>
        /// <returns>符合条数</returns>
        protected int FindCore(int startIndex, PropertyDescriptor prop, object key)
        {
            // Get the property info for the specified property.
            PropertyInfo propInfo = typeof(T).GetProperty(prop.Name);
            T item;
            if (key != null)
            {
                // Loop through the items to see if the key
                // value matches the property value.
                for (int i = startIndex; i < Count; ++i)
                {
                    item = (T)Items[i];
                    if (propInfo.GetValue(item, null).Equals(key))
                        return i;

                }
            }
            return -1;
        }
        #endregion
        #region 查找对象
        /// <summary>
        /// 查找对象
        /// </summary>
        /// <param name="match">委托</param>
        /// <returns>泛型</returns>
        public T Find(Predicate<T> match)
        {
            T _finded = default(T);

            for (int i = 0; i < Count; i++)
            {
                T t = Items[i];
                if (match(t))
                {
                    _finded = t;
                    break;
                }

            }
            return _finded;
        }
        /// <summary>
        /// 查找对象
        /// </summary>
        /// <param name="startIndex">索引开始数</param>
        /// <param name="property">属性名称</param>
        /// <param name="key">属性值</param>
        /// <returns>查找到符合记录</returns>
        public int Find(int startIndex, string property, object key)
        {

            // Check the properties for a property with the specified name.
            PropertyDescriptorCollection _properties = TypeDescriptor.GetProperties(typeof(T));
            PropertyDescriptor _prop = _properties.Find(property, true);
            // If there is not a match, return -1 otherwise pass search to
            // FindCore method.
            if (_prop == null)
                return -1;
            else
                if (startIndex <= 0)
                    return FindCore(_prop, key);
                else
                    return FindCore(startIndex, _prop, key);
        }
        #endregion
        #region 查找符合记录集合
        /// <summary>
        /// 查找符合记录集合
        /// </summary>
        /// <param name="match">委托</param>
        /// <returns>符合条件的集合</returns>
        public IList<T> FindAll(Predicate<T> match)
        {

            IList<T> _findedList = null;
            if (Count > 0)
                _findedList = new List<T>();

            for (int i = 0; i < Count; i++)
            {
                T t = Items[i];
                if (match(t))
                {
                    _findedList.Add(t);
                }
            }
            return _findedList;
        }
        #endregion
        #region 移除对象
        /// <summary>
        /// 移除对象
        /// </summary>
        /// <param name="match">委托</param>
        /// <returns>移除记录条数</returns>
        public int Remove(Predicate<T> match)
        {
            int _result = 0;
            for (int i = 0; i < Count; i++)
            {
                T t = Items[i];
                if (match(t))
                {
                    RemoveItem(i);
                    i--;
                    _result++;
                }
            }
            return _result;
        }
        #endregion
        #endregion
    }

}
